package com.hiss.basic.system.service;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.hiss.basic.client.system.ISysDeptService;
import com.hiss.basic.client.system.ISysUserRoleService;
import com.hiss.basic.client.system.ISysUserService;
import com.hiss.basic.model.system.domain.SysDeptDomain;
import com.hiss.basic.model.system.domain.SysUserDomain;
import com.hiss.basic.model.system.request.*;
import com.hiss.basic.model.system.response.SysDeptQueryResponse;
import com.hiss.basic.model.system.response.SysUserQueryResponse;
import com.hiss.basic.starter.core.exception.BusinessException;
import com.hiss.basic.starter.core.helper.MapstructHelper;
import com.hiss.basic.starter.core.helper.ValidationHelper;
import com.hiss.basic.starter.mybatis.utils.PageUtils;
import com.hiss.basic.starter.security.helper.SecurityHelper;
import com.hiss.basic.system.helper.SysUserPasswordHelper;
import com.hiss.basic.system.mapper.SysUserMapper;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryChain;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.row.Db;
import com.mybatisflex.core.update.UpdateChain;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 系统用户 service impl
 */
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUserDomain> implements ISysUserService {

    @Resource
    private ISysDeptService sysDeptService;

    @Resource
    private ISysUserRoleService sysUserRoleService;

    @Override
    public SysUserDomain findByUsername(String username) {
        QueryWrapper wrapper = QueryWrapper.create().where(SysUserDomain::getUsername).eq(username).limit(1);
        return getOne(wrapper);
    }

    @Override
    public List<SysUserQueryResponse> findList(SysUserQueryRequest request) {
        QueryWrapper wrapper = QueryWrapper.create();
        if (ObjectUtil.isNotNull(request)) {
            wrapper.like(SysUserDomain::getUsername, request.getUsername(), StrUtil.isNotBlank(request.getUsername()));
            wrapper.like(SysUserDomain::getNickname, request.getNickname(), StrUtil.isNotBlank(request.getNickname()));
            wrapper.eq(SysUserDomain::getEnableStatus, request.getEnableStatus(), ObjectUtil.isNotNull(request.getEnableStatus()));
        }
        wrapper.orderBy(SysUserDomain::getCreateTime, false);

        return listAs(wrapper, SysUserQueryResponse.class);
    }

    @Override
    public Page<SysUserQueryResponse> findPageList(SysUserQueryRequest request) {
        QueryWrapper wrapper = QueryWrapper.create();
        if (ObjectUtil.isNotNull(request)) {
            wrapper.like(SysUserDomain::getUsername, request.getUsername(), StrUtil.isNotBlank(request.getUsername()));
            wrapper.like(SysUserDomain::getNickname, request.getNickname(), StrUtil.isNotBlank(request.getNickname()));
            wrapper.eq(SysUserDomain::getEnableStatus, request.getEnableStatus(), ObjectUtil.isNotNull(request.getEnableStatus()));
            wrapper.in(SysUserDomain::getId, request.getUserIds(), CollectionUtil.isNotEmpty(request.getUserIds()));

            if (ObjectUtil.isNotNull(request.getDeptId())) {
                List<SysDeptQueryResponse> deptList = sysDeptService.findChildrenList(ListUtil.toList(request.getDeptId()));
                if (CollectionUtil.isNotEmpty(deptList)) {
                    Set<Long> deptIdList = deptList.stream().map(SysDeptQueryResponse::getId).collect(Collectors.toSet());
                    deptIdList.add(request.getDeptId());
                    wrapper.in(SysUserDomain::getDeptId, deptIdList);
                } else {
                    wrapper.eq(SysUserDomain::getDeptId, request.getDeptId());
                }
            }
        }
        wrapper.orderBy(SysUserDomain::getCreateTime, false);

        Page page = PageUtils.getPage();
        return pageAs(page, wrapper, SysUserQueryResponse.class);
    }

    @Override
    public void create(SysUserCreateRequest request) {
        ValidationHelper.validate(request);

        long count = QueryChain.of(SysUserDomain.class)
                .and(query -> {
                    query.eq(SysUserDomain::getUsername, request.getUsername());
                }).count();
        if (count > 0) {
            throw new BusinessException("用户名已存在");
        }

        if (StrUtil.isNotBlank(request.getEmail())) {
            count = QueryChain.of(SysUserDomain.class)
                    .eq(SysUserDomain::getEmail, request.getEmail())
                    .count();

            if (count > 0) {
                throw new BusinessException("邮箱已存在");
            }
        }

        SysUserDomain domain = MapstructHelper.convert(request, SysUserDomain.class);
        domain.setPassword(SysUserPasswordHelper.encryptPassword());

        Db.tx(() -> {
            save(domain);

            if (CollectionUtil.isNotEmpty(request.getRoleIdList())) {
                sysUserRoleService.create(domain.getId(), request.getRoleIdList());
            }
            return Boolean.TRUE;
        });
    }

    @Override
    public void update(SysUserUpdateRequest request) {
        ValidationHelper.validate(request);

        if (SecurityHelper.isSuperAdmin(request.getId())) {
            throw new BusinessException("不允许操作系统管理员");
        }
        long count = QueryChain.of(SysUserDomain.class)
                .ne(SysUserDomain::getId, request.getId())
                .and(query -> {
                    query.eq(SysUserDomain::getUsername, request.getUsername());
                }).count();

        if (count > 0) {
            throw new BusinessException("用户名已存在");
        }

        if (StrUtil.isNotBlank(request.getEmail())) {
            count = QueryChain.of(SysUserDomain.class)
                    .ne(SysUserDomain::getId, request.getId())
                    .eq(SysUserDomain::getEmail, request.getEmail())
                    .count();

            if (count > 0) {
                throw new BusinessException("邮箱已存在");
            }
        }

        SysUserDomain updateDomain = MapstructHelper.convert(request, SysUserDomain.class);

        Db.tx(() -> {
            updateById(updateDomain);
            sysUserRoleService.removeByUserId(request.getId());
            sysUserRoleService.create(request.getId(), request.getRoleIdList());
            return Boolean.TRUE;
        });
    }

    @Override
    public void updateBasic(SysUserBasicUpdateRequest request) {
        ValidationHelper.validate(request);

        if (StrUtil.isNotBlank(request.getEmail())) {
            long count = QueryChain.of(SysUserDomain.class)
                    .ne(SysUserDomain::getId, request.getId())
                    .eq(SysUserDomain::getEmail, request.getEmail())
                    .count();

            if (count > 0) {
                throw new BusinessException("邮箱已存在");
            }
        }

        UpdateChain.of(SysUserDomain.class)
                .set(SysUserDomain::getNickname, request.getNickname())
                .set(SysUserDomain::getAvatar, request.getAvatar())
                .set(SysUserDomain::getEmail, request.getEmail())
                .set(SysUserDomain::getUpdateTime, LocalDateTime.now())
                .where(SysUserDomain::getId).eq(request.getId())
                .update();
    }

    @Override
    public void updatePassword(SysUserPasswordUpdateRequest request) {
        ValidationHelper.validate(request);

        if (!request.getNewPassword().equals(request.getConfirmPassword())) {
            throw new BusinessException("新密码与确认密码不一致");
        }
        SysUserDomain domain = getById(request.getUserId());
        if (ObjectUtil.isNull(domain)) {
            throw new BusinessException("用户不存在");
        }
        if (!domain.getPassword().equals(SysUserPasswordHelper.encryptPassword(request.getOldPassword()))) {
            throw new BusinessException("原始密码错误");
        }
        UpdateChain.of(SysUserDomain.class)
                .set(SysUserDomain::getPassword, SysUserPasswordHelper.encryptPassword(request.getNewPassword()))
                .set(SysUserDomain::getUpdateTime, LocalDateTime.now())
                .where(SysUserDomain::getId).eq(request.getUserId())
                .update();
    }

    @Override
    public void resetPassword(Long userId) {
        if (ObjectUtil.isNotNull(userId)) {
            if (SecurityHelper.isSuperAdmin(userId)) {
                throw new BusinessException("不允许操作系统管理员");
            }

            UpdateChain.of(SysUserDomain.class)
                    .set(SysUserDomain::getPassword, SysUserPasswordHelper.encryptPassword())
                    .set(SysUserDomain::getUpdateTime, LocalDateTime.now())
                    .where(SysUserDomain::getId).eq(userId)
                    .update();
        }
    }

    @Override
    public void remove(Long userId) {
        if (ObjectUtil.isNotNull(userId)) {
            if (SecurityHelper.isSuperAdmin(userId)) {
                throw new BusinessException("不允许操作系统管理员");
            }
            long count = QueryChain.of(SysDeptDomain.class).eq(SysDeptDomain::getLeaderId, userId).count();
            if (count > 0) {
                throw new BusinessException("存在负责部门，不允许删除");
            }

            Db.tx(() -> {
                // 删除用户角色关联关系
                sysUserRoleService.removeByUserId(userId);

                removeById(userId);
                return Boolean.TRUE;
            });
        }
    }
}
